package com.suduku.calc;

import com.suduku.entity.Box;
import com.suduku.util.SudoUtil;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 数链-多宝鱼（如果数字n在同一行或列中，只有两个空白格，在同一宫中两个空白格，
 * 并且其中有两个顶点的行列相同，
 * 则另外两个顶点的共同作用空白格，则不能有数字n） <br/>
 *
 * 测试数据：DataConstant.OTHER_SU_LIAN_J_01
 */
public class SuLianDingCalc extends AbstractCalc {

    /**
     * 1. 遍历所有数字
     * 2. 遍历所有宫，查找数字n只有两个空白格B1,B2
     * 3. 遍历所有行或列，查找数字n只有两个空白格B3,B4（不在同宫中）
     * 4. 校验B1B2，B3B4其中，有两个点处于同一列或行
     * 5. 如果处于符合条件，则判断 另外两点的共同作用空白格不能有数字n
     */
    @Override
    Box solve() {
        for(Integer n : Box.INIT_LIST) {
            for (Map.Entry<Integer, List<Box>> gEntry : getGentries()) {
                // 获取数字n出现的空白格
                List<Box> b1b2List = gEntry.getValue().stream()
                        .filter(b -> b.isBlank() && b.getCList().contains(n))
                        .collect(Collectors.toList());
                if(b1b2List.size() == 2) {
                    // 遍历行，获取B3,B4
                    Box clearBox = findAndClear(b1b2List, getXentries(), n, gEntry.getKey(), false);
                    if(clearBox != null) {
                        return clearBox;
                    }
                    clearBox = findAndClear(b1b2List, getYentries(), n, gEntry.getKey(), true);
                    if(clearBox != null) {
                        return clearBox;
                    }
                }
            }
        }
        return null;
    }

    /**
     * 功能描述: 查找交叉点，并且清理共同作用空白格 <br/>
     *
     * @param b1b2List B1B2两个空白点
     * @param entries 区域
     * @param n 候选值
     * @param g 当前宫下标
     * @param isY 是否列区域
     * @return "com.suduku.entity.Box"
     */
    private Box findAndClear(List<Box> b1b2List, Set<Map.Entry<Integer, List<Box>>> entries, Integer n, Integer g, Boolean isY) {
        for(Map.Entry<Integer, List<Box>> xEntry : entries) {
            List<Box> b3b4List = xEntry.getValue().stream()
                    .filter(b -> b.isBlank() && b.getG() != g && b.getCList().contains(n))
                    .collect(Collectors.toList());
            if(b3b4List.size() == 2 && SudoUtil.isTwoBox(b3b4List)) {
                // 查找交叉点，并且清理
                Box clearBox = findAndClear(b1b2List.get(0), b1b2List.get(1), b3b4List.get(0), b3b4List.get(1), n, isY);
                if(clearBox != null) {
                    return clearBox;
                }
                clearBox = findAndClear(b1b2List.get(1), b1b2List.get(0), b3b4List.get(0), b3b4List.get(1), n, isY);
                if(clearBox != null) {
                    return clearBox;
                }
                clearBox = findAndClear(b1b2List.get(0), b1b2List.get(1), b3b4List.get(1), b3b4List.get(0), n, isY);
                if(clearBox != null) {
                    return clearBox;
                }
                clearBox = findAndClear(b1b2List.get(1), b1b2List.get(0), b3b4List.get(1), b3b4List.get(0), n, isY);
                if(clearBox != null) {
                    return clearBox;
                }
            }
        }
        return null;
    }

    /**
     * 功能描述: 查找交叉点，并且清理共同作用空白格 <br/>
     *
     * @param b1 同宫中第一个点与B3同行或列
     * @param b2 同宫中第二个点
     * @param b3 同行或列中第一个点，与B1同行或列
     * @param b4 同行或列中第二个点
     * @param n 候选值
     * @param isY 是否列
     * @return "com.suduku.entity.Box"
     */
    private Box findAndClear(Box b1, Box b2, Box b3, Box b4, Integer n, Boolean isY) {
        // 清理共同作用空白格
        Box clearBox =  null;
        if(isY) {
            if(b1.getX() == b3.getX()) {
                clearBox = getBoxByXY(b4.getX(), b2.getY());
            }
        } else {
            if(b1.getY() == b3.getY()) {
                clearBox = getBoxByXY(b2.getX(), b4.getY());
            }
        }
        if(clearBox != null && clearBox.isBlank() && clearBox.getCList().contains(n)) {
            clearBox.removeCList(n);
            change(clearBox, SudoUtil.getList(b1, b2, b3, b4), n);
            return clearBox;
        }
        return null;
    }

}
